﻿using System;
using G.Model;
using System.Collections.Generic;

namespace G.Runtime
{
    public class CalcIntGameValue : IntGameValue
    {
        private readonly GamePlayer _Player;
        private readonly List<GameElement> _GameElements = new List<GameElement>();
        
        internal CalcIntGameValue(GameValueDef def, GamePlayer pPlayer)
            : base(def) 
        {
            _Player = pPlayer;
            _Player.Game.Elements.PlayerChangedEvent += OnPlayerChangingEvent;
            SyncElements();
        }

        public override int Value
        {
            get { return Calc(); }
        }

        protected override string FormatDisplayableValue()
        {
            return "" + Value;
        }

        private int Calc() 
        {
            int v = 0;
            foreach(GameElement e in _GameElements)
            {
                if (e.GameValues.Contains(Def.Name)) {
                    IntGameValue i = (IntGameValue)
                        e.GameValues[Def.Name];
                    v += i.Value;
                }
            }
            return v;
        }
        
        internal void SyncElements() 
        {
            foreach(GameElement e in _Player.Game.Elements)
            {
                if (e.Player != _Player.Name) 
                {
                    continue;
                }
                
                if (_GameElements.Contains(e))
                {
                    continue;
                }
                
                _GameElements.Add(e);
                
                if (e.GameValues.Contains(base.Def.Name)) 
                {
                    IntGameValue i = (IntGameValue)
                        e.GameValues[Def.Name];
                    i.ChangedEvent += OnChangeEvent;
                }
                
                e.GameValues.ChangedEvent += OnGameValuesChangeEvent;
            }
            
            RemoveOldElements();
            
            FireChangedEvent();
        }
        
        private void RemoveOldElements() 
        {
            List<GameElement> remove = new List<GameElement>();
            foreach(GameElement e in _Player.Game.Elements)
            {
                bool found = false;
                foreach(GameElement test in _Player.Game.Elements)
                {
                    if (test.Def.Name == e.Def.Name)
                    {
                        found = true;
                        break;
                    }
                }
                
                if (!found) 
                {
                    remove.Add(e);
                }
            }
            
            foreach(GameElement e in remove)
            {
                if (e.GameValues.Contains(base.Def.Name)) 
                {
                    IntGameValue i = (IntGameValue)
                        e.GameValues[Def.Name];
                    i.ChangedEvent -= OnChangeEvent;
                }
                
                e.GameValues.ChangedEvent -= OnGameValuesChangeEvent;
                _GameElements.Remove(e);
            }
        }
        
        private void OnPlayerChangingEvent(GameElement subject)
        {
            SyncElements();
            FireChangedEvent();
        }
        
        private void OnChangeEvent(GameValue var)
        {
            SyncElements();
            FireChangedEvent();
        }
        
        private void OnGameValuesChangeEvent(GameValues pGameValues)
        {
            SyncElements();
            FireChangedEvent();
        }
        
        public override string ToString()
        {
            return "" + Def.Name + "=" + Value;
        }
        
    }
    
}
